<template>
  <div id="webgl-container" ref="containerRef" class="webgl-container">
    <canvas id="webgl" class="webgl"/>
  </div>
</template>

<script setup>
import * as CANNON from 'cannon-es'
import * as THREE from 'three'
import { ref, onMounted, onUnmounted } from 'vue'

import { useThree } from '@/hooks/use-three-hook.js'

const containerRef = ref(null)
const { scene, camera, addAnimationCallback, initPhysics, world } = useThree()

const textureLoader = new THREE.TextureLoader()
const particleTexture = textureLoader.load('/textures/particles/raindrop-4.png')
particleTexture.colorSpace = THREE.SRGBColorSpace

// 雨滴粒子系统
let rainParticles = null
let rainGeometry = null
let rainMaterial = null

// 物理对象
let rainBodies = []
let rainBodiesPositions = []

// 风向控制
const windForce = new CANNON.Vec3(2, 0, 1) // 默认风向
const gravity = new CANNON.Vec3(0, -9.82, 0) // 重力

// 创建雨滴
const createRain = () => {
  // 减少雨滴数量以提高性能
  const count = 5000
  rainGeometry = new THREE.BufferGeometry()

  const positions = new Float32Array(count * 3)
  const velocities = new Float32Array(count * 3)
  const colors = new Float32Array(count * 3)

  // 初始化物理体数组
  rainBodies = []
  rainBodiesPositions = []

  for (let i = 0; i < count; i++) {
    const i3 = i * 3

    // 随机位置
    positions[i3] = (Math.random() - 0.5) * 100 // x
    positions[i3 + 1] = Math.random() * 50 + 10 // y
    positions[i3 + 2] = (Math.random() - 0.5) * 100 // z

    // 设置初始速度 - 降低下落速度和扰动速度
    velocities[i3] = (Math.random() - 0.5) * 0.5   // x 方向轻微扰动 (降低扰动)
    velocities[i3 + 1] = -(Math.random() * 3 + 2)  // y 方向下落速度 (降低下落速度)
    velocities[i3 + 2] = (Math.random() - 0.5) * 0.5   // z 方向轻微扰动 (降低扰动)

    // 设置颜色 - 让雨滴有透明度变化
    colors[i3] = 0.5 // r
    colors[i3 + 1] = 0.5 // g
    colors[i3 + 2] = 1.0 // b

    // 只为部分雨滴创建物理体（每10个创建1个物理体）
    if (i % 5 === 0) {
      const body = new CANNON.Body({
        mass: 0.01,
        position: new CANNON.Vec3(positions[i3], positions[i3 + 1], positions[i3 + 2]),
        shape: new CANNON.Particle(),
        linearDamping: 0.01
      })

      // 添加初始速度
      body.velocity.set(velocities[i3], velocities[i3 + 1], velocities[i3 + 2])
      world.value.addBody(body)
      rainBodies.push(body)
      rainBodiesPositions.push(i3)
    }
  }

  rainGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
  rainGeometry.setAttribute('velocity', new THREE.BufferAttribute(velocities, 3))
  rainGeometry.setAttribute('color', new THREE.BufferAttribute(colors, 3))

  // 创建雨滴材质
  rainMaterial = new THREE.PointsMaterial({
    map: particleTexture,
    size: 0.3,
    sizeAttenuation: true,
    transparent: true,
    opacity: 0.8,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
    vertexColors: true
  })

  // 创建粒子系统
  rainParticles = new THREE.Points(rainGeometry, rainMaterial)
  scene.value.add(rainParticles)
}

// 更新雨滴动画
const updateRain = (deltaTime) => {
  if (!rainGeometry) return

  const positions = rainGeometry.attributes.position.array
  const velocities = rainGeometry.attributes.velocity.array

  // 更新受物理控制的雨滴
  for (let i = 0; i < rainBodies.length; i++) {
    const body = rainBodies[i]
    const i3 = rainBodiesPositions[i]

    // 应用重力和风力
    body.force.set(0, 0, 0)
    body.applyForce(gravity.scale(body.mass), body.position)
    body.applyForce(windForce, body.position)

    // 更新 Three.js 粒子位置
    positions[i3] = body.position.x
    positions[i3 + 1] = body.position.y
    positions[i3 + 2] = body.position.z

    // 如果雨滴落到地面以下，重新设置到顶部
    if (body.position.y < -10) {
      body.position.set(
        (Math.random() - 0.5) * 100,
        Math.random() * 50 + 10,
        (Math.random() - 0.5) * 100
      )

      // 重新设置速度
      body.velocity.set(
        (Math.random() - 0.5) * 0.5,
        -(Math.random() * 3 + 2),
        (Math.random() - 0.5) * 0.5
      )
    }
  }

  // 更新不受物理控制的雨滴（使用简单的位置更新）
  for (let i = 0; i < positions.length; i += 3) {
    // 检查这个粒子是否受物理控制
    const isPhysicallyControlled = rainBodiesPositions.includes(i)
    if (isPhysicallyControlled) continue

    // 更新位置 - 移除了额外的系数，使用更自然的速度
    positions[i] += velocities[i] * deltaTime
    positions[i + 1] += velocities[i + 1] * deltaTime
    positions[i + 2] += velocities[i + 2] * deltaTime

    // 如果雨滴落到地面以下，重新设置到顶部
    if (positions[i + 1] < -10) {
      positions[i] = (Math.random() - 0.5) * 100
      positions[i + 1] = Math.random() * 50 + 10
      positions[i + 2] = (Math.random() - 0.5) * 100
    }
  }

  rainGeometry.attributes.position.needsUpdate = true
}

// 动态改变风向
const updateWind = () => {
  // 随时间动态改变风向，模拟自然风的变化
  const time = Date.now() * 0.001
  windForce.x = Math.sin(time * 0.3) * 1.5
  windForce.z = Math.cos(time * 0.2) * 1
}

// 初始化场景
const initScene = () => {
  initPhysics(CANNON)

  // 设置相机位置
  camera.value.position.set(0, 10, 20)
  camera.value.lookAt(0, 0, 0)

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.value.add(ambientLight)

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
  directionalLight.position.set(10, 20, 15)
  scene.value.add(directionalLight)

  // 创建地面（物理）
  const groundShape = new CANNON.Plane()
  const groundBody = new CANNON.Body({ mass: 0 })
  groundBody.addShape(groundShape)
  groundBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)
  groundBody.position.y = -10
  world.value.addBody(groundBody)

  // 创建可视地面
  const groundGeometry = new THREE.PlaneGeometry(100, 100)
  const groundMaterial = new THREE.MeshStandardMaterial({
    color: 0x333333,
    transparent: true,
    opacity: 0.5
  })
  const ground = new THREE.Mesh(groundGeometry, groundMaterial)
  ground.rotation.x = -Math.PI / 2
  ground.position.y = -10
  scene.value.add(ground)

  // 创建雨滴
  createRain()

  // 添加动画回调
  addAnimationCallback(updateRain)
  addAnimationCallback(updateWind)
}

onMounted(() => {
  if (containerRef.value) {
    // 初始化场景
    initScene()
  }
})

onUnmounted(() => {
  // 清理资源
  if (rainGeometry) {
    rainGeometry.dispose()
  }
  if (rainMaterial) {
    rainMaterial.dispose()
  }

  // 清理物理体
  for (let i = 0; i < rainBodies.length; i++) {
    world.value.remove(rainBodies[i])
  }
})
</script>
